﻿using System.ComponentModel.DataAnnotations;
using System.Reflection;
using BootstrapBlazor.Components;
using BPM.Web.Shared.Data;
using Omu.ValueInjecter;
namespace BPM.Web.Shared.Extensions;

/// <summary>
/// 可枚举对象扩展
/// </summary>
internal static class EnumerableExtensions
{
    /// <summary>
    /// 转换成目标对象
    /// </summary>
    /// <typeparam name="TSource">自身类型</typeparam>
    /// <typeparam name="TDestination">目标类型</typeparam>
    /// <param name="source">要转换的对象</param>
    /// <returns></returns>
    public static IEnumerable<TDestination> Adapts<TSource, TDestination>(this IEnumerable<TSource> source)
        where TDestination : class, new()
    {
        if (source == null)
            return Enumerable.Empty<TDestination>();

        return source.Select(x => Mapper.Map<TSource, TDestination>(x));
    }

    /// <summary>
    /// 判断是否有值
    /// </summary>
    /// <typeparam name="TSource">自身类型</typeparam>
    /// <param name="source"></param>
    /// <returns></returns>
    public static bool HasValue<TSource>(this IEnumerable<TSource>? source)
        => source != null && source.Any();

    /// <summary>
    /// 存在值时执行
    /// </summary>
    /// <param name="value"></param>
    /// <param name="func"></param>
    /// <returns></returns>
    public static TResult HasValueFor<TSource, TResult>(this IEnumerable<TSource>? source, Func<IEnumerable<TSource>, TResult> func)
        where TResult : class, new()
        => source != null && source.Any() ? func.Invoke(source) : new TResult();

    /// <summary>
    /// 获取指定枚举类型的枚举值集合，默认通过 DisplayAttribute DescriptionAttribute 标签显示 DisplayName 支持资源文件 回退机制显示字段名称
    /// </summary>
    /// <param name="type"></param>
    /// <param name="addtionalItem"></param>
    /// <returns></returns>
    public static IEnumerable<SelectedItem> ToDisplaySelectList(this Type type, SelectedItem? addtionalItem = null)
    {
        var ret = new List<SelectedItem>();
        if (addtionalItem != null)
        {
            ret.Add(addtionalItem);
        }

        if (type.IsEnum())
        {
            var t = Nullable.GetUnderlyingType(type) ?? type;
            foreach (var val in Enum.GetNames(t))
            {
                var field = t.GetField(val);
                var display = field?.GetCustomAttribute<DisplayAttribute>(true);
                if (display != null)
                {
                    var value = display.Prompt ?? val;
                    var text = display?.Name ?? value;
                    ret.Add(new SelectedItem(value, text) { GroupName = display?.GroupName ?? "Unclassified" });
                }
            }
        }
        return ret;
    }

    /// <summary>
    /// 构造树节点（必须继承ITreeNode接口）
    /// </summary>
    /// <param name="nodes"></param>
    /// <param name="rootParentId">顶级节点的父节点Id(默认0)</param>
    /// <returns></returns>
    public static List<TItem> BuildTreeNode<TItem>(this IEnumerable<TItem>? nodes, long rootParentId = 0L)
        where TItem : class, ITreeNode<TItem, long>
    {
        var result = new List<TItem>();
        if (nodes != null)
        {
            foreach (var u in nodes)
            {
                BuildChildNodes(nodes, u, new List<TItem>());
            }
            foreach (var u in nodes)
            {
                if (rootParentId == u.GetPid())
                    result.Add(u);
            }
        }
        return result;
    }

    /// <summary>
    /// 构造子节点集合
    /// </summary>
    /// <param name="totalNodes"></param>
    /// <param name="node"></param>
    /// <param name="childNodeList"></param>
    private static void BuildChildNodes<TItem>(IEnumerable<TItem> totalNodes, TItem node, List<TItem> childNodeList)
        where TItem : class, ITreeNode<TItem, long>
    {
        var nodeSubList = new List<TItem>();
        foreach (var u in totalNodes)
        {
            if (u.GetPid().Equals(node.GetId()))
                nodeSubList.Add(u);
        }
        nodeSubList.ForEach(u => BuildChildNodes(totalNodes, u, new List<TItem>()));
        childNodeList.AddRange(nodeSubList);
        node.Children = childNodeList;
    }
}

